/****************************************************************************
 *
 *  LinuxChatty
 *  Copyright (C) 2010, David Hsu.
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 ***************************************************************************/
#include "StringUtil.h"
#include <string>
#include <vector>

using namespace std;

void StringUtil::WordWrapText(const string& text, vector<string>& output,
    unsigned int width)
{
	// Loops through the words of the body text and splits the body into
	// different lines stored in each index of the vector.
	// Note that I can't find an easier way than this because splitting it word
	// by word doesn't work when we still want to catch '\n' characters in order
	// to split it, and word for word can skip \n if it is directly at the end
	// of a word with no space, so we'll scan it character by character.
	string word, lineStr;
	char ch = 0;
	for (unsigned int i = 0; i < text.length(); i++)
	{
		ch = text[i];
		
		// Checks the character to see what to do. If it is a newline, add the
		// current line string to the array and create a new line. If it is a
		// space, then we finished a word and check to see if we need to wrap
		// it around.
		if (ch == '\n')
		{
			AddWord(word, lineStr, output, width, ch);
			output.push_back(lineStr);
			lineStr.clear();
		}
		else if (ch == ' ')
		{
			AddWord(word, lineStr, output, width, ch);
		}
		else
		{
			word += ch;
		}
	}
	
	// At the very end, if the line string still has data, add it to the body
	// array. If the last word exceeds the width of the textbox, then move it to
	// the next line.
	if (!word.empty())
	{
		AddWord(word, lineStr, output, width, 0);
	}
	
	// If the lineStr isn't empty, then add the line first, then add the word.
	// Also add another line, even if it is empty, if the last character read is
	// a new line
	if (!lineStr.empty() || ch == '\n')
	{
		output.push_back(lineStr);
	}
}

void StringUtil::AddWord(string& word, string& line, vector<string>& output,
    unsigned int width, const char ch)
{
	// If the length of the word and current line string is greater than the
	// number of columns, then we create a new line while adding the previous
	// line string.  Note that if the line string is empty and the word is long,
	// then we split it into the width sizes and add them to the array.
	// The extra 1 is the space that will be added before adding the word.
	if (word.length() + line.length() + 1 > width)
	{
		do
		{
			if (line.empty())
			{
				// Keep spliting the word on the width until the word length is
				// smaller than the width
				while( word.length() > width )
				{
					output.push_back(word.substr(0, width));
					word = word.substr(width, word.length());
				}
			}
			else
			{
				output.push_back(line);
				line.clear();
			}
		} while( word.length() > width );
		line = word + ' ';
	}
	else
	{
		line += word + ' ';
	}
	word.clear();
}
